﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TournamentOrganizerWPF
{
    static class MatchMaking
    {
        public static ObservableCollection<Table> TableList = new ObservableCollection<Table>(); 

        public static ObservableCollection<Match> MatchPlayersFirstRound(ObservableCollection<Player> playerList, ObservableCollection<string> locations, int matchCount)
        {
            //Create a list of players not matched (yet)
            var playersNotMatched = new ObservableCollection<Player>();
            var matchId = matchCount + 1;
            var tablenumber = 1;
            for (var i = 0; i < playerList.Count/2; i++)
            {

                TableList.Add(new Table(tablenumber));
                tablenumber++;
            }

            foreach (var player in playerList)
            {
                playersNotMatched.Add(player);
            }

            var eligiblePlayers = new List<Player>();
            var matches = new ObservableCollection<Match>();
            Player selectedPlayer;
            Player selectedOpponent = null;
            Match match;
            int currentTableNo = 1;
            Random rand = new Random();
            int selectedOpponentNo;

            int locationCount;
            int locationCountMax;
            string mostCommonLocation = "";

            do
            {
                //Find the most common home location
                locationCount = 0;
                locationCountMax = 0;

                foreach (var location in locations)
                {
                    locationCount = playersNotMatched.Count(player => player.HomeLocation.Equals(location));

                    if (locationCount > locationCountMax)
                    {
                        locationCountMax = locationCount;
                        mostCommonLocation = location;
                    }
                }

                //Select the first remaining player in the list 
                selectedPlayer = playersNotMatched.First(player => player.HomeLocation.Equals(mostCommonLocation));

                //remove the selected player from the list
                playersNotMatched.Remove(selectedPlayer);

                //Find all players where player's homelocation is not equal to the current selected player's homelocation 
                eligiblePlayers = playersNotMatched.Where(player => player.HomeLocation != selectedPlayer.HomeLocation).ToList();
                    
                //If there's only players left from the same location, choose a random one from the ones remaining
                if (eligiblePlayers.Count == 0)
                {
                    selectedOpponentNo = rand.Next(0, playersNotMatched.Count());
                    selectedOpponent = playersNotMatched[selectedOpponentNo];
                }
                else //There's at least one eligible player, select one of them.
                {
                    selectedOpponentNo = rand.Next(0, eligiblePlayers.Count());
                    selectedOpponent = eligiblePlayers[selectedOpponentNo];
                }

                match = new Match(matchId, selectedPlayer, selectedOpponent, currentTableNo);

                matchId++;

                matches.Add(match);

                //Remove the players from the 'not matched' list, the players have been matched
                playersNotMatched.Remove(selectedOpponent);

                //And select the next table
                currentTableNo++;
            } while (playersNotMatched.Count > 0);

            var newList = (from activematches in matches
                           orderby activematches.TableNo ascending 
                           select activematches).ToList();

            matches.Clear();

            foreach (var item in newList)
            {
                matches.Add(item);
            }

            return matches;
        }


        public static ObservableCollection<Match> MatchPlayersNextRound(ObservableCollection<Player> playerList, int matchCount)
        {
           
            int matchId = matchCount + 1;
            List<Player> playersNotMatched = playerList.ToList();
            List<Player> eligiblePlayers = new List<Player>();
            ObservableCollection<Match> matches = new ObservableCollection<Match>();
            Match match;
            int currentTableNo = 1;

            Player currentPlayer = null;
            Player opponent = null;

            TableList.Clear();
            int tablenumber = 1;
            for (var i = 0; i < playerList.Count / 2; i++)
            {

                TableList.Add(new Table(tablenumber));
                tablenumber++;
            }

            //Find and sort all players
            eligiblePlayers = (from players in playersNotMatched
                               where players.isActive == true
                               orderby players.ControlPoints descending
                               orderby players.Sos descending
                               orderby players.Wins descending
                               select players).ToList();

            while (eligiblePlayers.Count > 0)
            {
                int allTableUsed = 0;
                bool hasPlayedOnTable = true;
                currentPlayer = eligiblePlayers.First();
                eligiblePlayers.Remove(currentPlayer);

                opponent = eligiblePlayers.First(player => player.Opponents.Contains(currentPlayer) == false);
                while (hasPlayedOnTable)
                {
                    if (allTableUsed > 1)
                    {
                        //currentTableNo = TableList.First(table => !table.IsUsed).TableNumber;
                        //TableList.First(table => !table.IsUsed).IsUsed = true;
                        foreach (var table in TableList)
                        {
                            if (!table.IsUsed)
                            {
                                currentTableNo = table.TableNumber;
                                table.IsUsed = true;
                                hasPlayedOnTable = false;
                                break;
                            }
                        }

                    }
                    else if (IsTableUsed(currentTableNo))
                    {
                       
                        currentTableNo++;
                        if (currentTableNo > TableList.Count)
                        {
                            currentTableNo = 1;
                            allTableUsed++;
                        }
                    }
                    else if (currentPlayer.CheckTable(currentTableNo) || opponent.CheckTable(currentTableNo))
                    {
                        currentTableNo++;
                        if (currentTableNo > TableList.Count)
                        {
                            currentTableNo = 1;
                            allTableUsed++;
                        }
                    }
                    else
                    {
                        foreach (var table in TableList)
                        {
                            if(table.TableNumber == currentTableNo)
                            {
                                table.IsUsed = true;
                                hasPlayedOnTable = false;
                                break;
                            }
                        }
                    }
                }

                match = new Match(matchId, currentPlayer, opponent, currentTableNo);
                matches.Add(match);
                matchId++;

                eligiblePlayers.Remove(currentPlayer);
                eligiblePlayers.Remove(opponent);
 
            }

            foreach (var table in TableList)
            {
                table.IsUsed = false;
            }
            var newList = (from activematches in matches
                           orderby activematches.TableNo ascending 
                               select activematches).ToList();

            matches.Clear();

            foreach (var item in newList)
            {
                matches.Add(item);
            }   

            return matches;
        }

        private static bool IsTableUsed(int tableNumber)
        {
            foreach (var table in TableList)
            {
                if (table.TableNumber == tableNumber && table.IsUsed)
                {
                    return true;
                }
            }
            return false;
        }
    }
}
